#ifndef UNIT_H_
#define UNIT_H_

#include "../Object.h"
#include "../Resource.h"
#include "../Point3.h"
#include "UnitAspects/UnitAspect.h"
#include "../../Interfaces/UnitVisitor.h"
#include "../Commands/Command.h"

#include "../../boostPtrNames.h"

#include <map>
#include <vector>
#include <queue>

namespace OOInterface {



class Player;
typedef boost::shared_ptr< const Player > ConstPlayerPtr;

typedef std::vector< ConstUnitAspectPtr > UnitAspects;

typedef std::queue< OOInterface::ConstCommandPtr > CommandQueue;

class Unit: public Object
{
public:
	Unit();
	virtual ~Unit();

	virtual std::string toString() const;

	void accept( UnitVisitor& v ) const;

	OOInterface::Point3f getLocation() const { return _loc; }
	int getX() const { return _loc.getX(); }
	int getY() const { return _loc.getY(); }
	int getZ() const { return _loc.getZ(); }
	int getXSize() const { return _xSize; }
	int getZSize() const { return _zSize; }

	CommandQueue getCommandQueue() const { return _commandQueue; }

	int getID() const { return _id; }
	const std::string& getName() const { return _name; }
	ConstPlayerPtr getOwner() const { return _owner; }

	float getHealth() const { return _health; }
	float getMaxHealth() const { return _maxHealth; }
	float getBuildTime() const { return _buildTime; }
	bool isTransportable() const { return _isTransportable; }

	bool isIdle() const { return _isIdle; }
	void setIdle( bool idle ) { _isIdle = idle; }

	void setBuiltState( bool built ) { _isBuilt = built; }
	bool isBuilt() const { return _isBuilt; }

	float getResourceCost( const Resource& r ) const;
	float getResourceUpkeep( const Resource& r ) const;
	float getResourceStorage( const Resource& r ) const;
	float getResourceGeneration( const Resource& r ) const;

	void setLocation( OOInterface::Point3f p ) { _loc = p; }
	void setX( unsigned int x ) { _loc.setX( x ); }
	void setY( unsigned int y ) { _loc.setY( y ); }
	void setZ( unsigned int z ) { _loc.setZ( z ); }
	void setSize( int x, int z ) { _xSize = x; _zSize = z; }

	void setHealth( float health ) { _health = health; }
	void setMaxHealth( float max ) { _maxHealth = max; }
	void setBuildTime( float time ) { _buildTime = time; }
	void setTransportability( bool trans ) { _isTransportable = trans; }

	void addCommand( OOInterface::ConstCommandPtr cmd ) { _commandQueue.push( cmd ); }
	void popCommandQueue() { if( !_commandQueue.empty() ) _commandQueue.pop(); }
	void clearCommandQueue() { while( !_commandQueue.empty() ) _commandQueue.pop(); }

	void setID( int id ) { _id = id; }
	void setName( const std::string& name ) { _name = name; }
	void setOwner( ConstPlayerPtr owner ) { _owner = owner; }

	void addResourceCost( const Resource& r, float cost );
	void addResourceUpkeep( const Resource& r, float upkeep );
	void addResourceStorage( const Resource& r, float storage );
	void addResourceGeneration( const Resource& r, float generation );

	void addAspect( ConstUnitAspectPtr aspect );
	void removeAspect( ConstUnitAspectPtr aspect );

private:
	std::string _name;
	//A unique id for this unit.
	int _id;

	ConstPlayerPtr _owner;

	//A container of all the UnitAspects that this Unit is composed of
	UnitAspects _aspects;

	//The x and y size that the unit takes up on the GameMap. Useful for pathfinding.
	unsigned int _xSize, _zSize;

	OOInterface::Point3f _loc;

	//The current health of the unit
	float _health;
	//The maximum health the unit can have under natural circumstances.
	float _maxHealth;

	typedef std::map< const Resource, float> ResourceMap;
	ResourceMap _resourceCosts;
	ResourceMap _resourceUpkeep;
	ResourceMap _resourceStorage;
	ResourceMap _resourceGeneration;

	CommandQueue _commandQueue;

	bool _isBuilt;

	bool _isIdle;

	float _buildTime; //Time it takes to construct this Unit.

	bool _isTransportable;

	/*
	 * TODO: Figure out how to deal with radar/LOS/sonar in aspect form?
	int losRadius; // These different radiuses are going to be a pain.
	int radarRadius;
	int sonarRadius;

	int jammerRadius;
	int sonarJamRadius;
	int seismicRadius;
	*/

	// Defensive/Offensive Traits:
	// TODO: Figure out how defense/offense should be handled
};

}

#endif /*UNIT_H_*/
